/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.easoftware.code.mb;

import com.excel2objects.common.excel.util.Configuration;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import net.easoftware.code.beans.Mes;
import net.easoftware.code.beans.TipoCargaDatos;
import net.easoftware.code.beans.cargas.threading.CargasFilteringThread;
import net.easoftware.code.beans.cargas.threading.CargasSavingThread;
import net.easoftware.code.beans.cargas.threading.CargasValidatorProcess;
import net.easoftware.code.beans.facade.CargaDatosFc;
import net.easoftware.code.beans.prime.TiposCargaConverter;
import net.easoftware.code.dao.CargasDao;
import net.easoftware.code.dao.CatalogosDao;
import net.easoftware.code.dao.RangosEmpresaDao;
import net.easoftware.code.dao.TasasCambioDao;
import net.easoftware.code.error.EaError;
import net.easoftware.code.util.FacesUtil;
import net.easoftware.code.util.Tools;
import org.apache.log4j.Logger;
import org.primefaces.model.UploadedFile;

/**
 *
 * @author eliu
 */
@SessionScoped
@Named
public class MbCargasArchivos implements Serializable {

    private final static Logger logger = org.apache.log4j.Logger.getLogger(MbCargasArchivos.class);
    @Inject
    CargasDao cargasDao;
    @Inject
    CargaDatosFc cargaDatos;
    @Inject
    CatalogosDao catalogosDao;
    @Inject
    TasasCambioDao tasasCambioDao;
    @Inject
    RangosEmpresaDao rangosDao;
    private UploadedFile archivoXLS;
    private TipoCargaDatos tipoCarga;
    private List<TipoCargaDatos> tiposCarga;
    private List<Mes> meses;
    private Integer noPaso = 0;
    private boolean stopChecking = false;
    private boolean proccesingDone = false;
    private boolean savingDone = false;
    private long timer;
    private List<String> consola = new LinkedList<>();
    private boolean cargaExiste;
    private String opcionCargaExistente;

    public String getOpcionCargaExistente() {
        return opcionCargaExistente;
    }

    public void setOpcionCargaExistente(String opcionCargaExistente) {
        this.opcionCargaExistente = opcionCargaExistente;
    }

    public boolean isCargaExiste() {
        return cargaExiste;
    }

    public void setCargaExiste(boolean cargaExiste) {
        this.cargaExiste = cargaExiste;
    }

    public long getTimer() {
        return timer;
    }

    public void setTimer(long timer) {
        this.timer = timer;
    }

    public boolean isProccesingDone() {
        return proccesingDone;
    }

    public void setProccesingDone(boolean proccesingDone) {
        this.proccesingDone = proccesingDone;
    }

    public boolean isSavingDone() {
        return savingDone;
    }

    public void setSavingDone(boolean savingDone) {
        this.savingDone = savingDone;
    }

    public List<String> getConsola() {
        return consola;
    }

    public void setConsola(List<String> consola) {
        this.consola = consola;
    }

    public boolean isStopChecking() {
        return stopChecking;
    }

    public void setStopChecking(boolean stopChecking) {
        this.stopChecking = stopChecking;
    }

    public Integer getNoPaso() {
        return noPaso;
    }

    public void setNoPaso(Integer noPaso) {
        this.noPaso = noPaso;
    }

    public List<Mes> getMeses() {
        if (this.meses == null) {
            this.meses = Tools.getMeses();
        }
        return meses;
    }

    public void setMeses(List<Mes> meses) {

        this.meses = meses;
    }

    public CargasDao getCargasDao() {
        return cargasDao;
    }

    public void setCargasDao(CargasDao cargasDao) {
        this.cargasDao = cargasDao;
    }

    public TipoCargaDatos getTipoCarga() {
        return tipoCarga;
    }

    public void setTipoCarga(TipoCargaDatos tipoCarga) {
        this.tipoCarga = tipoCarga;
    }

    public List<TipoCargaDatos> getTiposCarga() {
        if (tiposCarga == null || tiposCarga.isEmpty()) {
            tiposCarga = TiposCargaConverter.listaTipoCargaDatos;
        }
        return tiposCarga;
    }

    public void setTiposCarga(List<TipoCargaDatos> tiposCarga) {
        this.tiposCarga = tiposCarga;
    }

    public UploadedFile getArchivoXLS() {
        return archivoXLS;
    }

    public void setArchivoXLS(UploadedFile archivoXLS) {
        this.archivoXLS = archivoXLS;
    }

    public void copyFile(String fileName, InputStream in) {
        try {
            try (OutputStream out = new FileOutputStream(new File(fileName))) {
                int read = 0;
                byte[] bytes = new byte[1024];

                while (( read = in.read(bytes) ) != -1) {
                    out.write(bytes, 0, read);
                }

                in.close();
                out.flush();
            }

            System.out.println("New file created!");
        }
        catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    public void procesarArchivo() {
        if (archivoXLS == null) {
            FacesUtil.addMessagesError("Debe seleccionar un archivo!");
            return;
        }
        try {
            String newFileName = cargaDatos.getMes() + "-" + cargaDatos.getAnio();
            setConsola(new LinkedList<String>());
            setStopChecking(false);
            setNoPaso(1);
            if (TiposCargaConverter.listaTipoCargaDatos.indexOf(tipoCarga) >= 0) {
                setTimer(System.currentTimeMillis());
                Configuration.FILE_TYPE = archivoXLS.getFileName().endsWith("xls") ? 1 : 2;
                Configuration.DEFAULT_DATE_FORMAT = "dd/MM/yy";
                TipoCargaDatos tc = tiposCarga.get(TiposCargaConverter.listaTipoCargaDatos.indexOf(tipoCarga));
                tc.setLineasNegocio(catalogosDao.getAllLineasNegocio());
                tc.setUnidadesNegocio(catalogosDao.getAllUnidadesNegocio());
                tc.setRangosEmpresa(rangosDao.getAllRangos());
                tc.setSkipRows(cargaDatos.getSaltoFilas());
                tc.setFileNameData("c:/unologs/" + System.currentTimeMillis() + "-" + newFileName + "-" + tc.getTipo().getSimpleName().concat(Configuration.FILE_TYPE == 1 ? "xls" : "xlsx"));
                copyFile(tc.getFileNameData(), archivoXLS.getInputstream());
                Thread t = new Thread(tc);
                t.start();
                cargaDatos.setCargaDatos(tc);
                cargaDatos.setCantidaRegistros(0);
                cargaDatos.setHilos(new LinkedList<CargasSavingThread>());
                cargaDatos.setValidationProcess(new CargasValidatorProcess());
                tc.setCargaExistente(cargasDao.existeCarga(cargaDatos.getMes(), cargaDatos.getAnio(), tipoCarga.getTipo()));
                this.cargaExiste = ( tc.getCargaExistente() != null );
            } else {
                FacesUtil.addMessagesError("Proceso de carga invalido!");
            }
        }
        catch (EaError | IOException ex) {
            logger.error("Error de procesamiento", ex);
            FacesUtil.addMessagesError("Error procesando archivo!");
            stopChecking = true;
        }
    }

    public void guardarInformacion() {
        try {
            setTimer(System.currentTimeMillis());
            setStopChecking(false);
            setNoPaso(2);
            setConsola(new LinkedList<String>());
            boolean appendData = this.opcionCargaExistente != null && this.opcionCargaExistente.equalsIgnoreCase("1");
            cargasDao.guardarCargaDatos(cargaDatos, appendData);
        }
        catch (EaError ex) {
            logger.error("Error de almacenamiento", ex);
        }
    }

    public void regresar() {
        setNoPaso(0);
    }

    public void salir() {
        setNoPaso(0);
    }

    private long getDurationProcess() {
        timer = System.currentTimeMillis() - timer;
        return timer > 0 ? ( timer / 1000 ) : 0;
    }

    public void checkAvanceProccesing() {
        if (cargaDatos.getCargaDatos().isPreparingThreads()) {
            setConsola(new LinkedList<String>());
            getConsola().add("Esperando para procesar...");
        } else {
            int proc = 0;
            int running = 0;
            for (CargasFilteringThread t : cargaDatos.getCargaDatos().getFiltros()) {
                running += t.isRunning() ? 1 : 0;
                proc += t.getFilasProcesadas();
            }
            setConsola(new LinkedList<String>());
            getConsola().add("Procesando " + proc + " de " + cargaDatos.getCargaDatos().getRegistrosEnviados());
            logger.info("procc hilos corriendo: " + running);
            logger.info("procc hilos no corriendo: " + ( cargaDatos.getCargaDatos().getFiltros().size() - running ));
            logger.info(getConsola().get(getConsola().size() - 1));
            stopChecking = ( running == 0 );
            if (stopChecking) {
                setConsola(new LinkedList<String>());
                getConsola().add("Proceso finalizado en " + getDurationProcess() + " seg. ");
                getConsola().add(cargaDatos.getCargaDatos().getData().size() + " a guardar de " + cargaDatos.getCargaDatos().getRegistrosEnviados());
            }
        }
    }

    public void checkAvanceSaving() {
        int running = 0;
        int proc = 0;
        for (CargasSavingThread h : cargaDatos.getHilos()) {
            running = h.isRunning() ? ( running + 1 ) : running;
            proc += h.getFilasProcesadas();
        }
        setConsola(new LinkedList<String>());
        getConsola().add("Guardando " + proc + " de " + cargaDatos.getCargaDatos().getData().size());
        logger.info("saving hilos corriendo: " + running);
        logger.info("saving hilos no corriendo: " + ( cargaDatos.getHilos().size() - running ));
        if (running == 0) {
            if (!cargaDatos.getValidationProcess().isRunning()) {
                if (cargaDatos.getValidationProcess().isExecuted()) {
                    stopChecking = true;
                } else {
                    stopChecking = false;
                    cargaDatos.getValidationProcess().setDao(cargasDao);
                    cargaDatos.getValidationProcess().setTipoValidacion(cargaDatos.getCargaDatos().getTipo().getSimpleName());
                    cargaDatos.getValidationProcess().start();
                    setConsola(new LinkedList<String>());
                    getConsola().add("Valindando informacion de archivo!");
                }
            } else {
                stopChecking = false;
            }
        }
        if (stopChecking) {
            setConsola(new LinkedList<String>());
            getConsola().add("Proceso finalizado en " + getDurationProcess() + " seg.");
        }
    }
}
